package cn.bonoon.kernel.support.services.handler;

import javax.persistence.EntityManager;

import cn.bonoon.kernel.events.OperateEvent;
import cn.bonoon.kernel.support.entities.EntityTree;
import cn.bonoon.kernel.support.entities.Persistable;
import cn.bonoon.kernel.util.StringHelper;

/**
 * <pre>
 * 完整的树形结构，需要处理的字段包括：
 * 1.xpath
 * 2.size
 * 3.fullname
 * 
 * </pre>
 * @author jackson
 *
 */
public class EditTreeHandler<E extends EntityTree<E>> implements EditHandler{
	
	private final String selectChildren;
	private final Class<E> entityClass;
	
	public EditTreeHandler(Class<E> entityClass){
		this.entityClass = entityClass;
		selectChildren = "select x from " + entityClass.getName() + " x where x.parent.id=?";
	}
	
	@Override
	public final boolean insertHandler(EntityManager entityManager, OperateEvent event, Persistable entity) {
		@SuppressWarnings("unchecked")
		E node = (E)entity;
		E parent = node.getParent();
		if(null != parent){
			insertTree(entityManager, node, parent);
			//需要处理xpath的问题
			entityManager.persist(node);
			node.setXpath(parent.getXpath() + node.getId() + "/");
			parent.setSize(parent.getSize() + 1);//父节点只需要加1吧
			entityManager.merge(parent);
		}else{
			insertTree(entityManager, node);
			entityManager.persist(node);
			node.setXpath(node.getId() + "/");
		}
		entityManager.merge(node);
		return true;
	}
	
	protected void insertTree(EntityManager entityManager, E node, E parent){
		node.setFullName(parent.getFullName() + node.getName());
	}
	
	protected void insertTree(EntityManager entityManager, E node){
		node.setFullName(node.getName());
	}
	
	@Override
	public final boolean updateHandler(EntityManager entityManager, OperateEvent event, Persistable entity) {
		/*
		 * 这里是更新的处理，表示entity在数据库中就已经存在的了
		 */
		@SuppressWarnings("unchecked")
		E node = (E)entity;
		E parent = node.getParent();
		String oldXpath = node.getXpath();
		if(StringHelper.isEmpty(oldXpath)){
			if(null == parent){
				updateTree(entityManager, node);
			}else{
				updateTree(entityManager, node, parent);
			}
			updateChildren(entityManager, node);
		}else{
			String last = "/" + node.getId() + "/";
			if(oldXpath.length() > last.length()){
				//旧的记录是有父节点的。
				char[] chs = oldXpath.toCharArray();
				int endPoint = chs.length - last.length();
				int staPoint = endPoint - 1;
				for(;staPoint > 0; staPoint--){
					if(chs[staPoint] == '/'){
						staPoint++;
						break;
					}
				}
				Long oldParentId = Long.parseLong(new String(chs, staPoint, endPoint - staPoint));
//				Long oldParentId = Long.parseLong(new String(chs, staPoint, endPoint - staPoint + 1));
				if(null == parent){
					updateOldParent(entityManager, oldParentId);
					updateTree(entityManager, node);
					updateChildren(entityManager, node);
				}else if(!oldParentId.equals(parent.getId())){
					updateOldParent(entityManager, oldParentId);
					updateTree(entityManager, node, parent);
					updateChildren(entityManager, node);
				}
			}else if(null != parent){
				//旧记录没有父节点但新记录有父节点
				updateTree(entityManager, node, parent);
				updateChildren(entityManager, node);
			}
		}
		entityManager.merge(node);
		return true;
	}
	
	private void updateChildren(EntityManager entityManager, E node){
		int size = 0;
		for(E et : entityManager
				.createQuery(selectChildren, entityClass)
				.setParameter(1, node.getId())
				.getResultList()){
			et.setFullName(node.getFullName() + et.getName());
			et.setXpath(node.getXpath() + et.getId() + '/');
			updateChildren(entityManager, et);
			entityManager.merge(et);
			size++;
		}
		node.setSize(size);
	}

	protected void updateTree(EntityManager entityManager, E node, E parent) {
		parent.setSize(parent.getSize() + 1);
		entityManager.merge(parent);
		
		node.setXpath(xpath(parent, node));
		node.setFullName(parent.getFullName() + node.getName());
	}

	protected void updateTree(EntityManager entityManager, E node) {
		node.setXpath(node.getId() + "/");
		node.setFullName(node.getName());
	}

	private void updateOldParent(EntityManager entityManager, Long oldParentId) {
		//新的父节点为空，但旧的父节点不为空
		E oldParent = entityManager.find(entityClass, oldParentId);
		oldParent.setSize(oldParent.getSize() - 1);
		entityManager.merge(oldParent);
	}
	
	private String xpath(E parent, E node){
		String xpath = parent.getXpath() + node.getId() + "/";
		//需要处理树节点死循环的情况
		if(null != node.getXpath() && xpath.startsWith(node.getXpath())){
			//树节点的死循环
			throw new RuntimeException("树节点死循环！！");
		}
		return xpath;
	}
}
